﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlServerCe;
using System.Data;
using Shared;

namespace Tui
{
    public class DataEnumerable<T> : IEnumerable<T> where T : BusinessObject<T>, new()
    {
        protected readonly string _indexName;
        protected readonly object[] _indexValuesLowerLimit;
        protected readonly object[] _indexValuesUpperLimit;
        internal string IndexName { get { return _indexName; } }
        internal object[] IndexValuesLowerLimit { get { return _indexValuesLowerLimit; } }
        internal object[] IndexValuesUpperLimit { get { return _indexValuesUpperLimit; } }
        internal DataEnumerable(string indexName, object[] indexValuesLowerLimit, object[] indexValuesUpperLimit)
        {
            _indexName = indexName;
            _indexValuesLowerLimit = indexValuesLowerLimit;
            _indexValuesUpperLimit = indexValuesUpperLimit;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return GetEnumerableInternal().GetEnumerator();
        }

        protected IEnumerable<T> GetEnumerableInternal()
        {
            var bos = BusinessObjectSupport.GetSupporter(typeof(T));
            SqlCeResultSet rs = null;
            SqlCeConnection cnn = bos.ConnectionGet();
            try
            {
                using (SqlCeCommand cmd = new SqlCeCommand())
                {
                    cmd.Connection = cnn;
                    cmd.CommandType = CommandType.TableDirect;
                    cmd.CommandText = bos.TableName;

                    if (_indexName != null || IndexValuesLowerLimit != null || IndexValuesUpperLimit != null)
                    {
                        cmd.IndexName = _indexName ?? DatabaseInfo.GetPrimaryKeyName(cnn, bos.TableName);

                        if (IndexValuesLowerLimit != null && IndexValuesLowerLimit == IndexValuesUpperLimit)
                            cmd.SetRange(DbRangeOptions.Prefix, IndexValuesLowerLimit, null);
                        else
                            cmd.SetRange(DbRangeOptions.Default, IndexValuesLowerLimit, IndexValuesUpperLimit);
                    }

                    rs = cmd.ExecuteResultSet(ResultSetOptions.None);
                }
                var p = ObjectReaderWriter.GetTransferer<T>(rs);
                while (rs.Read())
                {
                    T t = new T();
                    p(rs, t);
                    yield return t;
                }
            }
            finally
            {
                if (rs != null) rs.Dispose();
                bos.ConnectionRelease(cnn);
            }
        }


        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            foreach (T t in GetEnumerableInternal()) yield return t;
        }


        public DataEnumerable<T> WithIndex(string indexName, params object[] indexValues)
        {
            return new DataEnumerable<T>(indexName, indexValues, indexValues);
        }
        public DataEnumerable<T> IndexMatches(params object[] indexValues)
        {
            return new DataEnumerable<T>(_indexName, indexValues, indexValues);
        }
        public DataEnumerable<T> IndexGTE(params object[] indexValues)
        {
            return new DataEnumerable<T>(_indexName, indexValues, _indexValuesUpperLimit);
        }
        public DataEnumerable<T> IndexLTE(params object[] indexValues)
        {
            return new DataEnumerable<T>(_indexName, _indexValuesLowerLimit, indexValues);
        }
        public DataEnumerable<T> IndexBetween(object lowerRangeLimit, object upperRangeLimit)
        {
            return new DataEnumerable<T>(_indexName, new object[] { lowerRangeLimit }, new object[] { upperRangeLimit });
        }
        public DataEnumerable<T> IndexBetween(object upperRange1Limit, object upperRange2Limit, object lowerRange1Limit, object lowerRange2Limit)
        {
            return new DataEnumerable<T>(_indexName, new object[] { lowerRange1Limit, lowerRange2Limit }, new object[] { upperRange1Limit, upperRange2Limit });
        }
        public DataEnumerable<T> IndexBetween(object lowerRange1Limit, object lowerRange2Limit, object lowerRange3Limit, object upperRange1Limit, object upperRange2Limit, object upperRange3Limit)
        {
            return new DataEnumerable<T>(_indexName, new object[] { lowerRange1Limit, lowerRange2Limit, lowerRange3Limit }, new object[] { upperRange1Limit, upperRange2Limit, upperRange3Limit });
        }


    }
}
